package com.las.bot.cmd.game;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.las.bot.common.Constant;
import com.utils.JsonUtils;
import com.utils.RedisUtils;
import com.utils.card.CardUtil;
import com.utils.card.RuleUtil;
import com.jfinal.kit.StrKit;
import com.las.annotation.BotCmd;
import com.las.cmd.BaseCommand;
import com.las.utils.mirai.CmdUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

@BotCmd(funName = "斗地主")
public class DdzCommand extends BaseCommand {

    private Logger logger = LoggerFactory.getLogger(DdzCommand.class);

    private final Object lock = Constant.SUCCESS;


    public DdzCommand() {
        super("我要报名", "", "我要退出", "我要出牌", "我要看牌", "我要退房");
    }

    @Override
    public void execute(Long userId, Long id, Integer type, String command, ArrayList<String> args) {
        //开始实现功能
        String gameParams = null;
        if (args.size() > 0) {
            StringBuilder sb = new StringBuilder();
            for (String s : args) {
                sb.append(s).append(" ");
            }
            gameParams = sb.toString();
        }
        if (StrKit.notBlank(gameParams)) {
            //<>《》！:#! 用户习惯带着些符号，需要屏蔽为空格
            gameParams = gameParams.replaceAll("<", " ");
            gameParams = gameParams.replaceAll(">", " ");
            gameParams = gameParams.replaceAll("《", " ");
            gameParams = gameParams.replaceAll("》", " ");
            gameParams = gameParams.replaceAll("！", " ");
            gameParams = gameParams.replaceAll(":", " ");
            gameParams = gameParams.replaceAll("：", " ");
            gameParams = gameParams.replaceAll("#", " ");
            gameParams = gameParams.replaceAll("!", " ");
        }

        //我要退出
        if (command.startsWith("我要退出")) {
            // 退出就是强制结束游戏，清空所有key

            //确保玩家是在私聊？并且在群里使用需要提示尽可能私聊机器人
            if (type == 1) {
                CmdUtil.sendMessage("请私聊机器人发送该指令", userId, id, type);
                return;
            }

            //确保玩家是否有join报名的信息
            Object joinObj = RedisUtils.get("ddz:join:" + userId.toString());
            if (null == joinObj) {
                CmdUtil.sendMessage("您都还未报名！", userId, id, type);
                return;
            }

            //确保游戏状态是否正在游戏中
            Object gameObj = RedisUtils.get("ddz:played:" + userId.toString());
            if (null == gameObj) {
                CmdUtil.sendMessage("游戏还未开始！", userId, id, type);
                return;
            }

            String room = joinObj.toString();
            quitGame(room, userId.toString());
        }

        //我要退房
        if (command.startsWith("我要退房")) {
            if (type == 1) {
                CmdUtil.sendMessage("请私聊机器人发送指令", userId, id, type);
                return;
            }
            Object obj = RedisUtils.get("ddz:played:" + userId);
            if (null != obj) {
                CmdUtil.sendMessage("您已经在游戏中，不允许退房~\n可以输入指令：我要退出", userId, id, type);
            } else {
                //游戏没开始前,并且报了名的可以退房
                //join报名的信息
                Object joinObj = RedisUtils.get("ddz:join:" + userId);
                if (null == joinObj) {
                    CmdUtil.sendMessage("您都还未报名咋退房？逗我呢~", userId, id, type);
                    return;
                }
                String room = joinObj.toString();
                //移除map中的userId
                RedisUtils.hdel("ddz:play:" + room, userId.toString());
                RedisUtils.del("ddz:join:" + userId.toString());

                CmdUtil.sendMessage("退房成功", userId, id, type);
            }

        }

        //我要报名（参加）
        if (command.startsWith("我要报名")) {
            if (type == 1) {
                CmdUtil.sendMessage("请私聊机器人发送指令：我要报名", userId, id, type);
                return;
            }
            Object game = RedisUtils.get("ddz:played:" + userId.toString());
            if (null != game) {
                CmdUtil.sendMessage("您已经在游戏中，不允许再参加", userId, id, type);
            } else {
                //游戏没开始前，可以参加，但是要确保每个人只能在一个房间！！！
                Object joinObj = RedisUtils.get("ddz:join:" + userId.toString());
                if (null != joinObj) {
                    String hadRoom = joinObj.toString();
                    Map map = RedisUtils.hmget("ddz:play:" + hadRoom);
                    CmdUtil.sendMessage("您已经报过名！不能重复报名！\n房间：" + hadRoom + "，目前人数有" + map.size() + "人\n可以退房再来报名房间~\n指令：我要退房", userId, id, type);
                    return;
                }
                if (StrKit.isBlank(gameParams)) {
                    CmdUtil.sendMessage("请在指令后面带房间名", userId, id, type);
                    return;
                }

                String room = gameParams.trim();
                synchronized (lock) {
                    Map map = RedisUtils.hmget("ddz:play:" + room);
                    //Map<String, Object> map = JSONObject.parseObject(JSONObject.toJSONString(objMap), new TypeReference<Map<String, Object>>(){});
                    if (map.size() < 3) {
                        map.put(userId.toString(), type + "#" + id);//后续保存方便广播
                        RedisUtils.hmset("ddz:play:" + room, map);
                        //RedisUtils.expire("ddz:play:" + room, Constant.MAX_SESSION_TIME);
                        CmdUtil.sendMessage("房间:" + room + ",已有" + map.size() + "人报名，您报名成功", userId, id, type);
                        RedisUtils.set("ddz:join:" + userId, room);

                        //当最后一个玩家报名成功，开始广播给三个玩家私信
                        map = RedisUtils.hmget("ddz:play:" + room);
                        if (!map.isEmpty() && map.size() == 3) {
                            //设置状态变为游戏中(时效1小时)
                            //redis.setex("ddz:room:" + room, 60 * 60, "1");
                            sendAll(map, room);
                            //之后设置ddz:play时效性为120分钟，防止有人重复报名此房间
                            //RedisUtils.expire("ddz:play:" + room, Constant.MAX_SESSION_TIME);
                            //设置最初的上一张牌和玩家ID为-1字符串
                            RedisUtils.set("ddz:roomlc:" + room, "-1");
                            RedisUtils.set("ddz:roomld:" + room, "-1");
                        }

                    } else {
                        CmdUtil.sendMessage("房间:" + room + ",已有" + map.size() + "报名，您报名失败", userId, id, type);
                    }
                }


            }

        }

        //我要看牌
        if (command.startsWith("我要看牌")) {
            //确保玩家是在私聊？并且在群里使用需要提示尽可能私聊机器人
            if (type == 1) {
                CmdUtil.sendMessage("请私聊机器人发送该指令", userId, id, type);
                return;
            }

            //确保玩家是否有join报名的信息
            Object joinObj = RedisUtils.get("ddz:join:" + userId.toString());
            if (null == joinObj) {
                CmdUtil.sendMessage("您都还未报名，也可能有人退出已终止游戏！", userId, id, type);
                return;
            }

            //确保游戏状态是否正在游戏中
            Object gameObj = RedisUtils.get("ddz:played:" + userId.toString());
            if (null == gameObj) {
                CmdUtil.sendMessage("游戏还未开始，请耐心等玩家进房间，也可能有人退出已终止游戏！", userId, id, type);
                return;
            }

            String room = joinObj.toString();
            String cardInfo = gameObj.toString();
            ArrayList<String> list = (ArrayList<String>) JSON.parseArray(cardInfo, String.class);

            Object hostObj = RedisUtils.get("ddz:roomhost:" + room);
            assert hostObj != null;
            String hostInfo = hostObj.toString();
            String[] split = hostInfo.split("@");
            //看牌的时候这个没啥用
            //String hostQQ = split[0];
            String jsonStr = split[1];
            List<JSONObject> userList = JsonUtils.getJsonArrayByJsonString(jsonStr);
            for (int i = 0; i < userList.size(); i++) {
                JSONObject object = userList.get(i);
                if (object.getString("qq").equals(String.valueOf(userId))) {
                    //找到自己的信息，打印牌面
                    if (i == 0) {
                        CmdUtil.sendMessage("我是地主的牌：\n" + list, userId, id, type);
                    } else {
                        CmdUtil.sendMessage("我是农民" + i + "的牌：\n" + list, userId, id, type);
                    }
                }
            }

        }

        //我要出牌
        if (command.startsWith("我要出牌")) {
            //确保玩家是在私聊？并且在群里使用需要提示尽可能私聊机器人
            if (type == 1) {
                CmdUtil.sendMessage("请私聊机器人发送该指令", userId, id, type);
                return;
            }

            //确保玩家是否有join报名的信息
            Object joinObj = RedisUtils.get("ddz:join:" + userId.toString());
            if (null == joinObj) {
                CmdUtil.sendMessage("您都还未报名，也可能有人退出已终止游戏！", userId, id, type);
                return;
            }
            //确保游戏状态是否正在游戏中
            Object gameObj = RedisUtils.get("ddz:played:" + userId.toString());
            if (null == gameObj) {
                CmdUtil.sendMessage("游戏还未开始，不允许出牌，也可能有人退出已终止游戏！", userId, id, type);
                return;
            }

            if (StrKit.isBlank(gameParams)) {
                CmdUtil.sendMessage("请输入牌面信息", userId, id, type);
                return;
            }

            String room = joinObj.toString();
            String cardInfo = gameParams;
            //拿到上一个玩家的card，最初是-1字符串
            String lastCardStr = RedisUtils.get("ddz:roomlc:" + room).toString();

            //拿到上一个玩家的Id，最初是-1字符串
            String lastId = RedisUtils.get("ddz:roomld:" + room).toString();

            //出牌之前，检查是否轮到自己出牌！
            Object hostObj = RedisUtils.get("ddz:roomhost:" + room);
            assert hostObj != null;
            String hostInfo = hostObj.toString();
            String[] split = hostInfo.split("@");
            String hostQQ = split[0];
            String lastQQ = hostQQ;//在后面有一个redis设置有用到
            String jsonStr = split[1];
            List<JSONObject> userList = JsonUtils.getJsonArrayByJsonString(jsonStr);
            if (String.valueOf(userId).equals(hostQQ)) {
                //说明是自己出牌

                //需要拿到当前玩家的牌
                String cardObj = RedisUtils.get("ddz:played:" + userId).toString();
                ArrayList<String> list = (ArrayList<String>) JSON.parseArray(cardObj, String.class);

                logger.info("我的牌：" + list);

                // 广播发消息，除了自己的(发消息出去并且设置下个host之前比较规则)
                StringBuilder lastHost = new StringBuilder();
                StringBuilder lastUser = new StringBuilder();
                for (int i = 0; i < userList.size(); i++) {
                    JSONObject object = userList.get(i);
                    if (object.getString("qq").equals(hostQQ)) {
                        if (i == 0) {
                            lastHost.append("地主").append(" 出牌是：").append(cardInfo.toUpperCase());
                            lastUser.append("地主");
                        } else {
                            lastHost.append("农民").append(i).append(" 出牌是：").append(cardInfo.toUpperCase());
                            lastUser.append("农民").append(i);
                        }

                        String newHost;
                        //找到自己当时不用给自己发！必须要找下一个hostQQ是谁？
                        if (i == userList.size() - 1) {
                            //农民2 下一个是 地主，变为0
                            newHost = userList.get(0).getString("qq");
                        } else {
                            //前面的只需要 找 i + 1
                            newHost = userList.get(i + 1).getString("qq");
                        }
                        if (null != newHost) {
                            //就在这里比较！！！

                            boolean tag = false;
                            if (lastId.equals(String.valueOf(userId))) {
                                //自己获得主动权，重新发牌
                                logger.info("玩家 " + userId + " 获得主动权");
                                tag = true;

                            }

                            String info = cardInfo.toUpperCase().trim();
                            if (info.equalsIgnoreCase("pass")) {
                                if (tag) {
                                    //自己拿到主动权还pass？
                                    CmdUtil.sendMessage("您已经拿到主动权了，必须出牌！", userId, id, type);
                                    return;

                                }
                                if ("-1".equals(lastCardStr)) {
                                    //第一个玩家必须出牌
                                    CmdUtil.sendMessage("您是地主，最开始必须出牌！", userId, id, type);
                                    return;
                                }
                                logger.info(lastUser.toString() + " 已跳过");
                                lastHost.delete(0, lastHost.length());
                                lastHost.append(lastUser.toString()).append(" 已跳过");
                            } else {

                                String cardType = RuleUtil.checkCard(info, list);
                                logger.info("规则类型：" + cardType);
                                if (!RuleUtil.ERROR.equals(cardType)) {
                                    if (!"-1".equals(lastCardStr)) {
                                        //比较之前需要看双方牌数目是否一致(除了炸弹之外)
                                        if (lastCardStr.length() != info.length() && !RuleUtil.Bomb.equals(cardType) && !tag) {
                                            logger.info("牌面数目有误");
                                            CmdUtil.sendMessage("牌面数目有误", userId, id, type);
                                            return;
                                        } else {
                                            //校验牌面的大小规则(玩家自己获得主动权就不用再和自己比较)
                                            if (tag || RuleUtil.compare(info, lastCardStr)) {
                                                RuleUtil.removeCard(info, list);
                                                lastCardStr = info;

                                                //到这里证明是成功的
                                                logger.info("移除后的牌：" + list);
                                                if (list.size() == 0) {
                                                    gameOver(room, lastUser.toString());
                                                    return;
                                                }
                                                lastHost.append("\n剩余牌数：").append(list.size());
                                                RedisUtils.set("ddz:played:" + userId, JsonUtils.getJsonString(list));

                                            } else {
                                                logger.info("你的牌小于上一个玩家的牌");
                                                CmdUtil.sendMessage("你的牌小于上一个玩家的牌" + lastCardStr, userId, id, type);
                                                return;
                                            }
                                        }
                                    } else {
                                        //证明是最初第一个玩家先出牌！
                                        RuleUtil.removeCard(info, list);
                                        if (list.size() == 0) {
                                            gameOver(room, lastUser.toString());
                                            return;
                                        }
                                        lastHost.append("\n剩余牌数：").append(list.size());
                                        lastCardStr = info;

                                        //到这里证明是成功的
                                        RedisUtils.set("ddz:played:" + userId, JsonUtils.getJsonString(list));
                                    }

                                } else {
                                    logger.info("牌面有误");
                                    CmdUtil.sendMessage("牌面有误", userId, id, type);
                                    return;
                                }


                                //设置上一次用户ID的信息
                                RedisUtils.set("ddz:roomld:" + room, lastQQ);

                            }

                            //设置下一个发牌的人的作为host
                            RedisUtils.set("ddz:roomhost:" + room, newHost + "@" + JsonUtils.getJsonString(userList));
                            //设置上一次发牌的信息
                            RedisUtils.set("ddz:roomlc:" + room, lastCardStr);

                            //之后就是广播了
                            for (JSONObject other : userList) {
                                String qq = other.getString("qq");
                                if (!qq.equals(String.valueOf(userId))) {
                                    String typeInfo = other.getString("type");
                                    String[] spType = typeInfo.split("#");
                                    String typeStr = spType[0];
                                    long gId = 0L;
                                    if (!"0".equals(typeStr)) {
                                        gId = Long.parseLong(spType[1]);
                                    }
                                    CmdUtil.sendMessage(lastHost.toString(), Long.parseLong(qq), gId, Integer.parseInt(typeStr));

                                }
                            }

                        }
                    }
                }
                CmdUtil.sendMessage("出牌成功，等待下一个玩家出牌", userId, id, type);
            } else {
                //不是自己出牌告诉玩家是谁出牌？0是地主 1是农民一号 2是农民二号
                String rule = "\n出牌顺序：地主>农民1>农民2";
                for (int i = 0; i < userList.size(); i++) {
                    JSONObject object = userList.get(i);
                    logger.info("当前出牌人是：" + hostQQ + "，对应出牌玩家：" + object);
                    if (object.getString("qq").equals(hostQQ)) {
                        if (i == 0) {
                            CmdUtil.sendMessage("当前是地主先出牌" + rule, userId, id, type);
                        } else {
                            CmdUtil.sendMessage("当前是农民" + i + "先出牌" + rule, userId, id, type);
                        }
                    }
                }
            }

        }
    }

    private void quitGame(String room, String quitUser) {
        //广播所有人宣布哪个玩家胜利，并且打印牌面，以及清空redis所有数据

        Object hostObj = RedisUtils.get("ddz:roomhost:" + room);
        assert hostObj != null;
        String hostInfo = hostObj.toString();
        String[] split = hostInfo.split("@");
        //String hostQQ = split[0];
        String jsonStr = split[1];
        List<JSONObject> userList = JsonUtils.getJsonArrayByJsonString(jsonStr);
        for (int i = 0; i < userList.size(); i++) {
            JSONObject obj = userList.get(i);
            String qq = obj.getString("qq");

            StringBuilder sb = new StringBuilder();
            sb.append("\n玩家 ").append(quitUser).append(" 退出，游戏终止\n\n");
            for (int j = 0; j < userList.size(); j++) {
                JSONObject all = userList.get(j);
                String user = all.getString("qq");
                String cardStr = RedisUtils.get("ddz:played:" + user).toString();
                ArrayList<String> list = (ArrayList<String>) JSON.parseArray(cardStr, String.class);
                if (j == 0) {
                    sb.append("地主").append(" 剩余牌是：").append(list).append("\n\n");
                } else {
                    sb.append("农民").append(j).append(" 剩余牌是：").append(list).append("\n\n");
                }
            }

            String typeInfo = obj.getString("type");
            String[] spType = typeInfo.split("#");
            String typeStr = spType[0];
            long gId = 0L;
            if (!"0".equals(typeStr)) {
                gId = Long.parseLong(spType[1]);
            }
            CmdUtil.sendMessage(sb.toString(), Long.parseLong(qq), gId, Integer.parseInt(typeStr));
        }

        for (JSONObject object : userList) {
            String qq = object.getString("qq");
            RedisUtils.del("ddz:played:" + qq);
            RedisUtils.del("ddz:join:" + qq);
        }

        //开始清空 ddz:roomhost
        RedisUtils.del("ddz:roomhost:" + room);
        RedisUtils.del("ddz:roomlc:" + room);
        RedisUtils.del("ddz:roomld:" + room);
        RedisUtils.del("ddz:play:" + room);

    }

    private void gameOver(String room, String winUser) {
        //广播所有人宣布哪个玩家胜利，并且打印牌面，以及清空redis所有数据

        Object hostObj = RedisUtils.get("ddz:roomhost:" + room);
        assert hostObj != null;
        String hostInfo = hostObj.toString();
        String[] split = hostInfo.split("@");
        //String hostQQ = split[0];
        String jsonStr = split[1];
        List<JSONObject> userList = JsonUtils.getJsonArrayByJsonString(jsonStr);
        for (int i = 0; i < userList.size(); i++) {
            JSONObject obj = userList.get(i);
            String qq = obj.getString("qq");

            StringBuilder sb = new StringBuilder();
            sb.append("\n恭喜 ").append(winUser).append(" 获胜\n\n");
            for (int j = 0; j < userList.size(); j++) {
                JSONObject all = userList.get(j);
                String user = all.getString("qq");
                String cardStr = RedisUtils.get("ddz:played:" + user).toString();
                ArrayList<String> list = (ArrayList<String>) JSON.parseArray(cardStr, String.class);
                if (j == 0) {
                    sb.append("地主").append(" 剩余牌是：").append(list).append("\n\n");
                } else {
                    sb.append("农民").append(j).append(" 剩余牌是：").append(list).append("\n\n");
                }
            }

            String typeInfo = obj.getString("type");
            String[] spType = typeInfo.split("#");
            String typeStr = spType[0];
            long gId = 0L;
            if (!"0".equals(typeStr)) {
                gId = Long.parseLong(spType[1]);
            }
            CmdUtil.sendMessage(sb.toString(), Long.parseLong(qq), gId, Integer.parseInt(typeStr));
        }

        for (JSONObject object : userList) {
            String qq = object.getString("qq");
            RedisUtils.del("ddz:played:" + qq);
            RedisUtils.del("ddz:join:" + qq);
        }

        //开始清空 ddz:roomhost
        RedisUtils.del("ddz:roomhost:" + room);
        RedisUtils.del("ddz:roomlc:" + room);
        RedisUtils.del("ddz:roomld:" + room);
        RedisUtils.del("ddz:play:" + room);

    }

    private void sendAll(Map map, String room) {
        Set set = map.keySet();
        ArrayList<JSONObject> userList = new ArrayList<>();
        LinkedHashMap<Long, String> users = new LinkedHashMap<>();
        Random random = new Random();
        int index = random.nextInt(3);// 0 1 2
        int count = 0;
        long host = 0L;
        String fType = "0";
        for (Object qq : set) {
            String type = map.get(qq).toString();//估计大多数都是0，有些是临时会话2
            long userId = Long.parseLong(qq.toString());
            if (count == index) {
                host = userId;
                fType = type;
                break;
            }
            count++;
        }
        users.put(host, fType);//将地主排在第一！
        JSONObject object = new JSONObject();
        object.put("qq", host);
        object.put("type", fType);
        userList.add(object);

        count = 0;
        for (Object qq : set) {
            String type = map.get(qq).toString();//估计大多数都是0，有些是临时会话2
            long userId = Long.parseLong(qq.toString());
            if (count != index) {
                users.put(userId, type);//非地主的，按默认循环排进去

                object = new JSONObject();
                object.put("qq", userId);
                object.put("type", type);
                userList.add(object);
            }
            count++;
        }

        //设置当前发牌的人的作为host
        RedisUtils.set("ddz:roomhost:" + room, host + "@" + JsonUtils.getJsonString(userList));

        //准备生成牌
        CardUtil cardUtil = new CardUtil();
        cardUtil.initCard();

        Set<Long> qqKeys = users.keySet();//并且是按照第一个是地主
        int runHost = 1;
        for (Long qqKey : qqKeys) {
            ArrayList<String> card = cardUtil.getCard(runHost);
            logger.info("玩家" + runHost + "的牌：" + card);
            RedisUtils.set("ddz:played:" + qqKey, JsonUtils.getJsonString(card));
            String typeInfo = users.get(qqKey);
            String[] split = typeInfo.split("#");
            String type = split[0];
            long gId = 0L;
            if (!"0".equals(type)) {
                gId = Long.parseLong(split[1]);
            }
            logger.info("准备发牌：" + qqKey + "，临时会话：" + type + ",群：" + gId);
            if (runHost == 1) {
                CmdUtil.sendMessage("房间:" + room + "\n\n您是地主\n" + card.toString(), qqKey, gId, Integer.parseInt(type));
            } else {
                CmdUtil.sendMessage("房间:" + room + "\n\n您是农民" + (runHost - 1) + "\n" + card.toString(), qqKey, gId, Integer.parseInt(type));
            }

            String rule = "牌面里的\nB 是大王\nX 是小王\nT 是10\n\n出牌指令是：我要出牌 33445566\n看牌指令是：我要看牌\n我要出牌 pass 表示跳过";
            CmdUtil.sendMessage(rule, qqKey, gId, Integer.parseInt(type));
            runHost++;

        }

    }


}
